package com.boyinet.imesh2json.netty.client

import com.boyinet.imesh2json.netty.handler.ReConnectHandler
import com.boyinet.imesh2json.netty.policy.ExponentialBackOffRetry
import com.boyinet.imesh2json.netty.policy.NoneRetry
import com.boyinet.imesh2json.netty.policy.RetryPolicy
import io.netty.bootstrap.Bootstrap
import io.netty.channel.*
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.SocketChannel
import io.netty.channel.socket.nio.NioSocketChannel
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component


@Component
class TransformClient {

    private val bootstrap: Bootstrap

    companion object {
        var socketChannel: Channel? = null
    }

    val log: Logger = LoggerFactory.getLogger(TransformClient::class.java)

    lateinit var ip: String
    var port: Int = -1
    lateinit var retryPolicy: RetryPolicy

    init {
        // bootstrap 可重用, 只需在TcpClient实例化的时候初始化即可.
        val workerGroup = NioEventLoopGroup()
        val reConnectHandler = ReConnectHandler(this@TransformClient)
        bootstrap = Bootstrap()
        bootstrap.group(workerGroup)
            .channel(NioSocketChannel::class.java)
            .option(ChannelOption.SO_KEEPALIVE, true)
            .handler(object : ChannelInitializer<SocketChannel>() {
                override fun initChannel(ch: SocketChannel) {
                    ch.pipeline().addLast(reConnectHandler)
                }
            })
    }

    fun connect(
        ip: String,
        port: Int,
        retryPolicy: RetryPolicy = ExponentialBackOffRetry(1000, Int.MAX_VALUE, 60 * 1000)
    ) {
        this.ip = ip
        this.port = port
        this.retryPolicy = retryPolicy
        connect()
    }

    fun connect() {
        log.info("${Thread.currentThread().name} ： connect running")
        val channelFuture = bootstrap.connect(ip, port).sync()

        log.info("${Thread.currentThread().name}：with lock connect running")

        channelFuture.addListener(object : ChannelFutureListener {
            override fun operationComplete(future: ChannelFuture) {
                if (!future.isSuccess) {
                    log.info("初始连接失败，执行重连...")
                    future.channel().pipeline().fireChannelInactive()
                }
            }
        })
        socketChannel = channelFuture.channel()
        log.info("初始连接成功")
    }

    fun disconnect() {
        retryPolicy = NoneRetry()
        socketChannel?.close()
    }
}